package moveresize;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.JComponent;
import javax.swing.SwingUtilities;

public class Delta {
	public enum STATE {BEGIN, IN_PROGRESS, END};
	
    public Delta(JComponent control) {
        this.component = control;
        attached = new AtomicBoolean(false);
    }
   
    protected void attach(Point displayRelativeStart) {
    	this.displayRelativeStart = displayRelativeStart;
    	attach();
    }
    
	public void attach() {
        if (attached.compareAndSet(false, true)) {
        	component.addMouseListener(mouseListener);
        	component.addMouseMotionListener(mouseMotionListener);
        }
    }

    public void dettach() {
        if (attached.compareAndSet(true, false)) {
        	component.removeMouseListener(mouseListener);
        	component.removeMouseMotionListener(mouseMotionListener);
        }
    }
    
    protected final JComponent component;
    private AtomicBoolean attached;
    private Point displayRelativeStart;
    
    MouseListener mouseListener = new MouseAdapter() {
		public void mousePressed(MouseEvent e) {
			processMouseEvent(e);
		}
		
		public void mouseReleased(MouseEvent e) {
			processMouseEvent(e);
		}
    };
    
    MouseMotionListener mouseMotionListener = new MouseMotionAdapter() {

		public void mouseMoved(MouseEvent e) {
			processMouseEvent(e);
		}
		
		public void mouseDragged(MouseEvent e) {
			processMouseEvent(e);
		}
    };
    
    private void processMouseEvent(MouseEvent event) {
        Point eventPoint = new Point(event.getX(), event.getY());
        try {
        	Point displayRelativeCurrent = new Point(eventPoint);
        	SwingUtilities.convertPointToScreen(displayRelativeCurrent, component);
        	switch (event.getID()) {
        	case MouseEvent.MOUSE_PRESSED:
        		displayRelativeStart = new Point(eventPoint);
        		SwingUtilities.convertPointToScreen(displayRelativeStart, component);
        		process(0, 0, STATE.BEGIN, event.getX(), event.getY());
        		break;
        	case MouseEvent.MOUSE_DRAGGED:
        		if (displayRelativeStart != null) {
        			process(displayRelativeCurrent.x - displayRelativeStart.x,
        					displayRelativeCurrent.y - displayRelativeStart.y,
        					STATE.IN_PROGRESS,
        					event.getX(), event.getY());
        		}
        		break;
        	case MouseEvent.MOUSE_RELEASED:
        		if (displayRelativeStart != null) {
        			process(displayRelativeCurrent.x - displayRelativeStart.x,
        					displayRelativeCurrent.y - displayRelativeStart.y,
        					STATE.END,
        					event.getX(), event.getY());
        			displayRelativeStart = null;
        		}
        		break;
        	}
        } finally {
        	setCursor(eventPoint);
        }
    }
    
    protected JComponent getComponent() {
        return component;
    }
   
    protected void process(int deltaX, int deltaY, STATE state, int x, int y) {
    	System.out.println(
    			"(" + deltaX + "," + deltaY + ") state=" + state
    			+ " at " + "(" + x + "," + y + ")"
    			);
    }
    
    protected void setCursor(Point eventPoint) {}
}